home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
telecomm
/
sticpsrc.lzh
/
SOURCE.ARC
/
NR4.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-20
|
18KB
|
725 lines
/* NET/ROM level 4 processing */
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "trace.h"
#include "timer.h"
#include "arp.h"
#include "ax25.h"
#include "netrom.h"
#ifdef NETROM4
unsigned nr_trtimeout = 60;
unsigned nr_trtries = 3;
unsigned nr_trackdelay = 3;
unsigned nr_trbusdelay = 180;
unsigned nr_trwindow = 4;
unsigned nr_trbacklog = 4;
unsigned nr_noactive = 900;
struct nr_circ *nr_circ[NR4NUMCIRC]; /* the circuit table */
#endif
extern char badcall[];
static void nr4_connect(),nr4ack(),nr4_state(),nr4_reset(),nrtrtime(),nrtrack();
static int nr4sendit();
static struct nr_circ *nr4_circptr(),*nr4_newcirc();
void nr4_close();
/* send IP datagrams across a NET/ROM network connection */
int
nr_send(bp,interface,gateway,precedence,delay,throughput,reliability)
struct mbuf *bp;
struct interface *interface; /* the "netrom" pseudo-iface */
int32 gateway;
char precedence;
char delay;
char throughput;
char reliability;
{
struct arp_tab *arp;
struct mbuf *hbp;
struct nr4hdr n4hdr;
struct ax25_addr dest;
dump(interface,IF_TRACE_OUT,TRACE_IP,bp); /* trace to "netrom" */
if ((arp = arp_lookup(interface,ARP_NETROM,gateway)) == NULLARP) {
free_p(bp); /* drop the packet if no route */
return -1;
}
/* new NET/ROM encapsulation method: put a NET/ROM transport */
/* header with opcode=protocol extension before the IP packet */
n4hdr.opcode = NR4PID;
n4hdr.family = PID_IP;
n4hdr.proto = PID_IP;
if ((hbp = htonnr4(&n4hdr)) == NULLBUF) {
free_p(bp); /* no space for level4 header */
return -1;
}
hbp->next = bp;
getaxaddr(&dest,arp->hw_addr); /* get destination call */
return nr_send3(hbp,&dest); /* send it to level 3 */
}
/* Process NET/ROM transport layer packets.
*/
void
nr4recv(bp)
struct mbuf *bp;
{
struct nr4hdr n4hdr;
struct mbuf *bph;
register struct nr_circ *circ;
if (ntohnr4(&n4hdr,&bp) < 0) { /* get transport header */
free_p(bp); /* bad header, ignore it */
return;
}
switch (n4hdr.opcode & NR4OMASK) { /* look at opcode bits */
case NR4PID: /* network protocol extension */
if (n4hdr.family == PID_IP && /* is it IP family? */
n4hdr.proto == PID_IP) /* IP protocol? */
ip_route(bp,0); /* send to the IP router */
else
free_p(bp); /* something else, ignore */
return;
case NR4CONRQ: /* connect request */
nr4_connect(&n4hdr);
if ((bph = htonnr4(&n4hdr)) != NULLBUF)
nr_send3(bph,&n4hdr.snode);
break;
#ifdef NETROM4
case NR4CONACK: /* connect acknowledge */
if ((circ = nr4_circptr(&n4hdr)) != NULLNRCIRC &&
circ->state == NR4STCPEND){
if (n4hdr.opcode & NR4CREFUSE) {
circ->d_reason = NR4REBUSY;
nr4_reset(circ);
} else {
ASSIGN(circ->your,n4hdr.my);
circ->window = min(n4hdr.window,nr_trwindow);
stop_timer(&circ->trtimer);
nr4_state(circ,NR4STCON);
}
}
break;
case NR4DISRQ: /* disconnect request */
if ((circ = nr4_circptr(&n4hdr)) != NULLNRCIRC){
ASSIGN(n4hdr.your,circ->your);
n4hdr.my.index = n4hdr.my.id = 0;
n4hdr.opcode = NR4DISACK;
if ((bph = htonnr4(&n4hdr)) != NULLBUF)
nr_send3(bph,&circ->dnode);
nr4_reset(circ);
}
break;
case NR4DISACK: /* disconnect acknowledge */
if ((circ = nr4_circptr(&n4hdr)) != NULLNRCIRC &&
circ->state == NR4STDPEND){
nr4_reset(circ);
}
break;
case NR4INFO: /* information */
if ((circ = nr4_circptr(&n4hdr)) != NULLNRCIRC &&
circ->state == NR4STCON){
start_timer(&circ->acktimer);/* send ACK/NAK after a while */
/* unless someone below does it */
if (circ->rxseq == n4hdr.txseq){ /* check sequence# */
circ->rxseq = n4hdr.txseq + 1; /* ok, update */
circ->mystate &= ~NR4NAK;
nr4ack(circ,&n4hdr); /* process ACK information */
append(&circ->rxasm,bp);/* assemble packets */
bp = NULLBUF;
if (!(n4hdr.opcode & NR4MORE)) { /* not MORE coming? */
enqueue(&circ->rxq,circ->rxasm);
circ->rxasm = NULLBUF;
if (circ->r_upcall != NULLVFP)
(*circ->r_upcall)(circ,len_q(circ->rxq));
if (len_q(circ->rxq) >= nr_trbacklog)
circ->mystate |= NR4CHOKE;
}
start_timer(&circ->noacttim); /* kick no-activity */
} else { /* bad sequence # */
if (uchar(n4hdr.txseq - circ->rxseq) <= circ->window)
circ->mystate |= NR4NAK; /* in window, NAK it */
/* (others are ignored) */
nr4ack(circ,&n4hdr); /* process ACK information */
}
}
break;
case NR4INFACK: /* information acknowledge */
if ((circ = nr4_circptr(&n4hdr)) != NULLNRCIRC &&
circ->state == NR4STCON)
nr4ack(circ,&n4hdr); /* process it */
break;
#endif
}
free_p(bp); /* free anything left over */
}
/* attach the NET/ROM interface. optionally set NET/ROM call too. */
int
nr_attach(argc,argv)
int argc;
char *argv[];
{
register struct ax25_call *axc;
struct ax25_addr hwaddr;
if (nr_interface != NULLIF) {
printf("netrom interface already attached\n");
return -1;
}
if (argc > 1) {
if (setcall(&hwaddr,argv[1]) < 0) {
printf(badcall,argv[1]);
return -1;
}
if((axc = cr_axcall(ax25_call,&hwaddr)) == NULLAXCALL)
return -1;
axc->flags |= MULTI_IF;
}
nr_arp();
if((nr_interface = (struct interface *)calloc(1,sizeof(struct interface))) == NULLIF)
return -1;
nr_interface->name = "netrom";
nr_interface->mtu = NR4ILEN;
nr_interface->send = nr_send;
if (argc > 1){ /* callsign specified? */
if((nr_interface->hwaddr = malloc(sizeof(struct ax25_addr))) == NULLCHAR)
return -1;
memcpy(nr_interface->hwaddr,(char *)&hwaddr,sizeof(struct ax25_addr));
}
nr_interface->next = ifaces;
ifaces = nr_interface;
return 0;
}
/* process incoming level 4 connect requests */
static void
nr4_connect (hdr)
register struct nr4hdr *hdr;
{
register struct nr_circ *circ;
extern void nr7_rxnr();
/* setup default response to reject the connect request */
ASSIGN(hdr->your,hdr->my);
hdr->my.index = hdr->my.id = 0;
hdr->opcode = NR4CONACK | NR4CREFUSE;
#ifdef NETROM4
if (nr_trtimeout < 60 || /* NET/ROM 4 inoperable? */
nr_trtries == 0 ||
nr_trackdelay == 0 ||
nr_trbusdelay < 60 ||
nr_trwindow == 0 ||
nr_noactive < 60)
return; /* reject connection */
if (hdr->window == 0 || /* bad window? */
valid_addr(&hdr->suser) != 0 || /* invalid source call? */
valid_addr(&hdr->snode) != 0) /* invalid source node? */
return; /* reject it */
if ((circ = nr4_newcirc(&hdr->your,&hdr->snode)) == NULLNRCIRC)
return; /* no space, refuse it */
/* got a circuit, initialize it and build CONACK */
ASSIGN(hdr->my,circ->my);
hdr->window = circ->window = min(hdr->window,nr_trwindow);
ASSIGN(circ->suser,hdr->suser);
nr4_state(circ,NR4STCON);
circ->trtimer.start = SEC2TICK(nr_trtimeout);
circ->trtimer.func = nrtrtime;
circ->acktimer.start = SEC2TICK(nr_trackdelay);
circ->acktimer.func = nrtrack;
circ->noacttim.start = SEC2TICK(nr_noactive);
circ->noacttim.func = nr4_close;
circ->trtimer.arg = circ->acktimer.arg = circ->noacttim.arg = (char *) circ;
start_timer(&circ->noacttim); /* start no-activity timer */
circ->r_upcall = nr7_rxnr; /* receive = NET/ROM cmds */
hdr->opcode &= ~NR4CREFUSE; /* accept connection */
#endif
}
#ifdef NETROM4
/* connect a NET/ROM l4 circuit */
struct nr_circ *
nr4_conn (dnode,snode,suser,r_upcall,t_upcall,s_upcall,user)
struct ax25_addr *dnode; /* destination node's call */
struct ax25_addr *snode; /* originating node's call */
struct ax25_addr *suser; /* originating user's call */
void (*r_upcall)(); /* Receiver upcall handler */
void (*t_upcall)(); /* Transmitter upcall handler */
void (*s_upcall)(); /* State-change upcall handler */
char *user; /* user ctrlblock pointer */
{
register struct nr_circ *circ;
int idx;
if (nr_trtimeout < 60 || /* NET/ROM 4 inoperable? */